package util;

import config.CommonConfig;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import message.Message;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

@Slf4j
public class MessageCodec extends ByteToMessageCodec<Message> {

  @Override
  protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
    // 设置魔数 4个字节
    out.writeBytes(new byte[]{'G', 'T', 'M', 'J'});
    // 设置版本号 1个字节
    out.writeByte(1);
    // 设置序列化方式 1个字节(0 jdk,1 json)
    out.writeByte(CommonConfig.getSerializerAlgorithm().ordinal());
    // 设置指令类型 1个字节
    out.writeByte(msg.getMessageType());
    // 设置请求序号 4个字节
    out.writeInt(msg.getSequenceId());

    // 获得序列化后的msg
    byte[] bytes = CommonConfig.getSerializerAlgorithm().serialize(msg);

    // 获得并设置正文长度 长度用4个字节标识
    out.writeInt(bytes.length);
    // 为了补齐为16个字节，填充1个字节的数据
    out.writeByte(0xff);
    // 设置消息正文
    out.writeBytes(bytes);
  }

  @Override
  protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
    // 获取魔数
    int magic = in.readInt();
    // 获取版本号
    byte version = in.readByte();
    // 获得序列化方式
    byte seqType = in.readByte();
    // 获得指令类型
    byte messageType = in.readByte();
    // 获得请求序号
    int sequenceId = in.readInt();
    // 获得正文长度
    int length = in.readInt();
    // 移除补齐字节
    in.readByte();
    // 获得正文
    byte[] bytes = new byte[length];
    in.readBytes(bytes, 0, length);
    Serializer.Algorithm algorithm = Serializer.Algorithm.values()[seqType];
    Class<?> aClass = Message.getMessageClass(messageType);
    Message message = (Message) algorithm.deserialize(aClass,bytes);

    // 将信息放入List中，传递给下一个handler
    out.add(message);

    log.debug("魔数 ,{}", magic);
    log.debug("版本号 ,{}", version);
    log.debug("指令类型 ,{}", messageType);
    log.debug("序列化方法 ,{}", seqType);
    log.debug("请求序号 ,{}", sequenceId);
    log.debug("正文长度 ,{}", length);
    log.debug("正文 ,{}", message);
  }
}